package com.zjdiepu.www.commpent;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Date;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

import com.aliyun.oss.ClientException;
import com.aliyun.oss.HttpMethod;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.internal.Mimetypes;
import com.aliyun.oss.model.Callback;
import com.aliyun.oss.model.GetObjectRequest;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.UploadFileRequest;
import com.zjdiepu.www.base.enums.type.ResultFlagType;
import com.zjdiepu.www.common.util.FileUtil;
import com.zjdiepu.www.config.OSSProperty;
import com.zjdiepu.www.util.ExceptionHelper;

/**
 * 项目名称：dp-base <br/> 
 * 类名称：OOSUtil <br/>  
 * 类描述：阿里云对象操作 <br/>    
 * 创建人：xiongxiaotun <br/> 
 * 创建时间：2017年3月27日 下午3:38:34  <br/>   
 * 修改人：xiongxiaotun <br/> 
 * 修改时间：2017年3月27日 下午3:38:34   <br/>  
 * 修改备注：    <br/> 
 * @version V1.0   <br/>
 */
@Component
public class OSSCommpent implements InitializingBean {
	private final Logger logger = LoggerFactory.getLogger(getClass());
	/*
	 * oss配置
	 */
	@Resource
	private OSSProperty ossProperty;
	/*
	 * ossClient客户端
	 */
	private OSSClient ossClient;
	
	/**
	 * @author xiongxiaotun <br/>
	 * @Title: uploadCheckPoint  <br/>
	 * @Description: 断点续传 <br/>
	 * @param localFilePath
	 * @param fileKey
	 * @param fileName
	 * @return
	 * @version V1.0  <br/>
	 */
	public boolean uploadCheckPoint(String localFilePath, String fileKey, String fileName) {
		return uploadCheckPoint(localFilePath, fileKey, fileName, null);
	}
	
	/**
	 * @author xiongxiaotun <br/>
	 * @Title: uploadCheckPoint  <br/>
	 * @Description: 断点续传 <br/>
	 * @param localFilePath
	 * @param fileKey
	 * @param fileName
	 * @param callback
	 * @return
	 * @version V1.0  <br/>
	 */
	public boolean uploadCheckPoint(String localFilePath, String fileKey, String fileName, Callback callback){
		if(StringUtils.isBlank(localFilePath) || StringUtils.isBlank(fileKey) || StringUtils.isBlank(fileName)) {
			ExceptionHelper.thow(ResultFlagType.PARAM_EMPTY.getCode().toString(), ResultFlagType.PARAM_EMPTY.getValue());
		}
		try {
			UploadFileRequest uploadFileRequest = new UploadFileRequest(ossProperty.getBucketName(), fileKey);
			// 指定上传的本地文件
			uploadFileRequest.setUploadFile(localFilePath);
			// 指定上传并发线程数
			uploadFileRequest.setTaskNum(5);
			// 指定上传的分片大小
			uploadFileRequest.setPartSize(1 * 1024 * 1024);
			// 开启断点续传
			uploadFileRequest.setEnableCheckpoint(true);
			//本地文件
			//检查上传情况的文件，默认在本地文件同目录
			File file = new File(localFilePath);
			ObjectMetadata objectMetadata = createMetadata(file.length(), fileName);
			uploadFileRequest.setObjectMetadata(objectMetadata);
			if(null != callback) {
				uploadFileRequest.setCallback(callback);
			}
			// 断点续传上传
			ossClient.uploadFile(uploadFileRequest);
			return true;
		} catch (Throwable e) {
			logger.error("阿里云断点续传失败.本地路径：{}，云端路径：{}，文件名称：{}。异常为：{}",localFilePath, fileKey, fileName, e);
			return false;
		}
		
	}

	/**
	 * 获取访问路径
	 * @param fileKey
	 * @return
	 */
	public String getUrlAndAuthorized(String fileKey) {
		Date expiration = new Date(System.currentTimeMillis() + ossProperty.getAuthorizedTime() * 1000);
		// 生成URL
		URL url = ossClient.generatePresignedUrl(ossProperty.getBucketName(), fileKey, expiration, HttpMethod.GET);
		try {
			URI uri = url.toURI();
			return uri.toString();
		} catch (URISyntaxException e) {
			logger.error("授权图片访问发生异常. 云端路径：{}。异常为：{}", fileKey, e);
			ExceptionHelper.thow("HTTP_ERROR_MSG_011", "授权图片访问发生异常");
			return null;
		}
	}
	
	/**
	 * @author xiongxiaotun <br/>
	 * @Title: download  <br/>
	 * @Description: 下载OSS对象到本地文件 <br/>
	 * @param fileKey
	 * @param savePath
	 * @return
	 * @version V1.0  <br/>
	 */
	public void download(String fileKey, String savePath) {
		logger.debug("download object to file start.");
		ossClient.getObject(new GetObjectRequest(ossProperty.getBucketName(), fileKey), new File(savePath));
		logger.debug("download object to file end.");
	}

	/**
	 * 上传文件：输入字节数据
	 * 
	 * @author xiongxiaotun
	 * @date 2016年9月8日 下午7:56:08
	 * @param fileKey
	 * @return
	 */
	public boolean upload(List<Byte> bytes, String fileKey) {
		if (null == bytes || StringUtils.isBlank(fileKey)) {
			return false;
		}
		byte[] fileContent = FileUtil.getFileContent(bytes);
		return upload(fileContent, fileKey);
	}
	
	/**
	 * @author xiongxiaotun <br/>
	 * @Title: upload  <br/>
	 * @Description:上传文件:输入流 <br/>
	 * @param input
	 * @param fileKey
	 * @param fileName
	 * @version V1.0  <br/>
	 */
	public boolean upload(InputStream input, String fileKey, String fileName) {
		return upload(input, fileKey, fileName, null);
	}
	
	/**
	 * @author xiongxiaotun <br/>
	 * @Title packageMetadata  <br/>
	 * @Description 生成文件元数据  <br/>
	 * @param size
	 * @param fileName (不是fileKey，而是本地对应的真实有意义的名称)
	 * @return
	 * @version V1.0  <br/>
	 */
	private ObjectMetadata createMetadata(long size, String fileName){
		// 创建上传Object的Metadata
		ObjectMetadata meta = new ObjectMetadata();
		meta.setContentLength(size);
		meta.setCacheControl("no-cache");
		meta.setHeader("Pragma", "no-cache");
		meta.setContentDisposition("inline;filename=" + fileName);
		String mimetype = Mimetypes.getInstance().getMimetype(fileName);
		meta.setContentType(mimetype);
		return meta;
	}
	
	/**
	 * @author xiongxiaotun <br/>
	 * @Title: upload  <br/>
	 * @Description:上传文件:字节数组 <br/>
	 * @param data
	 * @param fileKey
	 * @param fileName
	 * @param ossCallback 回调封装
	 * @version V1.0  <br/>
	 */
	public boolean upload(byte[] data, String fileKey, String fileName, Callback ossCallback) {
		byte[] buf = new byte[data.length];
		ByteArrayInputStream in = new ByteArrayInputStream(buf);
		in.read(data, 0, buf.length);
		return upload(in, fileKey, fileName, ossCallback);
	}
	
	/**
	 * @author xiongxiaotun <br/>
	 * @Title: upload  <br/>
	 * @Description:上传文件:输入流 <br/>
	 * @param input
	 * @param fileKey 文件oss标识
	 * @param fileName 文件名
	 * @param ossCallback 回调封装
	 * @version V1.0  <br/>
	 */
	public boolean upload(InputStream input, String fileKey, String fileName, Callback ossCallback) {
		try {
			if (StringUtils.isBlank(fileKey) || input == null || input == null) {
				return false;
			}
			long size = input.available();
			PutObjectRequest putObjectRequest = new PutObjectRequest(ossProperty.getBucketName(), fileKey, input); 
			putObjectRequest.setMetadata(createMetadata(size, fileName));
			if(null != ossCallback) {
				putObjectRequest.setCallback(ossCallback);
			}
			ossClient.putObject(putObjectRequest);
			return true;
		} catch (OSSException oe) {
			logger.error("阿里云文件上传失败. 云端路径：{}，文件名称：{}。异常为：{}", fileKey, fileName, oe);
        } catch (ClientException ce) {
        	logger.error("阿里云文件上传失败. 云端路径：{}，文件名称：{}。异常为：{}", fileKey, fileName, ce);
        }  catch (IOException e) {
        	logger.error("阿里云文件上传失败. 云端路径：{}，文件名称：{}。异常为：{}", fileKey, fileName, e);
		} finally {
			FileUtil.release(input, null);
		}
		return false;
	}

	/**
	 * 上传文件:字节数组
	 * 
	 * @param data
	 * @param fileKey
	 * @return
	 */
	public boolean upload(byte[] data, String fileKey) {
		if (fileKey == null || data == null || data.length == 0) {
			return false;
		}
		boolean success = false;
		// 创建上传Object的Metadata
		ObjectMetadata meta = new ObjectMetadata();
		// 必须设置ContentLength
		meta.setContentLength(data.length);
		// 设置contentType
		meta.setContentType(Mimetypes.getInstance().getMimetype(fileKey));
		try (ByteArrayInputStream in = new ByteArrayInputStream(data);){
			ossClient.putObject(ossProperty.getBucketName(), fileKey, in, meta);
			success = true;
		} catch (Throwable e) {
			logger.error("阿里云文件上传失败. 云端路径：{}。异常为：{}", fileKey, e);
		}
		return success;
	}
	
	/**
	 * 上传文件：文件对象
	 * 
	 * @author xiongxiaotun
	 * @date 2016年9月8日 下午7:56:08
	 * @param fileKey
	 * @return
	 */
	public boolean upload(File file, String fileKey) {
		if (null == file || StringUtils.isBlank(fileKey)) {
			return false;
		}
		ossClient.putObject(ossProperty.getBucketName(), fileKey, file);
		return true;
	}

	/**
	 * 删除文件
	 * @author xiongxiaotun
	 * @date 2016年9月8日 下午7:56:08
	 * @param fileKey
	 * @return
	 */
	public boolean remove(String fileKey) {
		if (StringUtils.isBlank(fileKey)) {
			return true;
		}
		ossClient.deleteObject(ossProperty.getBucketName(), fileKey);
		return true;
	}

	/**
	 * @author xiongxiaotun <br/>
	 * @Title: exist  <br/>
	 * @Description: 对象是否存在  <br/>
	 * @param fileKey
	 * @return
	 * @version V1.0  <br/>
	 */
	public boolean exist(String fileKey) {
		if (StringUtils.isBlank(fileKey)) {
			return false;
		}
		return ossClient.doesObjectExist(ossProperty.getBucketName(), fileKey);
	}
	
	/**
	 * @author xiongxiaotun <br/>
	 * @Title: init  <br/>
	 * @Description: 初始化方法的注解方式  <br/>
	 * @version V1.0  <br/>
	 */
	@PostConstruct
	public void init() {
		
	}

	/**
	 * @author xiongxiaotun <br/>
	 * @Title: destory  <br/>
	 * @Description: 销毁方法的注解方式  <br/>
	 * @version V1.0  <br/>
	 */
	@PreDestroy
	public void destory() {
		logger.debug("destory ossClient start...");
		if(null != ossClient) {
			ossClient.shutdown();
		}
		logger.debug("destory ossClient end.");
	}
	
	@Override
	public void afterPropertiesSet() throws Exception {
		logger.debug("create ossClient start...");
//		ossClient = new OSSClient(ossProperty.getClientEndPoint(), ossProperty.getKeyId(), ossProperty.getKeySecret());
//		String bucketName = ossProperty.getBucketName();
//		if(!ossClient.doesBucketExist(bucketName)){
//			ossClient.createBucket(bucketName);
//		}
//		// 白名单
//		String whiteList = ossProperty.getWhiteList();
//		if(StringUtils.isNotBlank(whiteList)  && !StringUtil.ASTERISK.equals(whiteList.trim())) {
//			List<String> refererList = new ArrayList<String>();
//			// 添加referer项
//			refererList.addAll(Arrays.asList(whiteList.split(",")));
//			// 允许referer字段为空，并设置Bucket Referer列表
//			BucketReferer br = new BucketReferer(true, refererList);
//			ossClient.setBucketReferer(bucketName, br);
//		}
		logger.debug("create ossClient end.");
	}
}
